﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using UnrealDebugger.Panels;
using System.IO;
using WeifenLuo.WinFormsUI.Docking;
using System.Threading;
using System.Reflection;

namespace UnrealDebugger
{
    public partial class UnrealDebuggerIDE : Form
    {
        #region Singleton
        
        private static UnrealDebuggerIDE _instance;
        private static Byte[] _signature = { 0x43, 0x61, 0x72, 0x6C, 0x6F, 0x73, 0x01, 0x4C, 0x6F, 0x70, 0x65, 0x7A, 0x01, 0x4D, 0x65, 0x6E, 0x65, 0x6E, 0x64, 0x65, 0x7A };

        private UnrealDebuggerIDE()
        {
        }

        private void Initialize()
        {
            CreatePanels();
            InitializeComponent();

            this._project = new Project();
            this._deserializeDockContent = new DeserializeDockContent(GetContentFromPersistString);

            this.OnDocumentOpened += new DocumentOpenedDelegate(OnDocumentShown);
        }

        public static UnrealDebuggerIDE Instance
        {
            get 
            {
                if (_instance == null || _instance.IsDisposed)
                {
                    _instance = new UnrealDebuggerIDE();
                    _instance.Initialize();
                }

                return _instance;
            }
        }

        #endregion

        #region Debugger Interface

        private Document _activeDocument = null;
        public Document ActiveDocument { get { return _activeDocument; } }

        private int _activeLine = -1;
        public int ActiveLine { get { return _activeLine; } }

        private int _activeCallstackPosition = -1;
        public int ActiveCallstackPosition { get { return _activeCallstackPosition; } }

        private int _activeCallstackDepth = 0;
        public int ActiveCallstackDepth { get { return _activeCallstackDepth; } }

        public void AttachDebugger()
        {
            this.Show();
            this.RaiseDebuggerAttached();
        }

        public void DetachDebugger()
        {
            this._activeLine = -1;
            this._activeDocument = null;
            this._activeCallstackPosition = -1;
            this._activeCallstackDepth = -1;

            this.RaiseDebuggerDetached();
        }

        #endregion

        private void UnrealDebuggerIDE_Load(object sender, EventArgs e)
        {
            LoadLayout();
            LoadProject();

            RegisterPanel(_outputPanel, "&Output Panel");
            RegisterPanel(_outlinePanel, "&Outline Panel");
            RegisterPanel(_explorerPanel, "&Explorer Panel");
            RegisterPanel(_callstackPanel, "&Callstack Panel");
            RegisterPanel(_localWatchPanel, "&Local Watch Panel");
            RegisterPanel(_globalWatchPanel, "&Global Watch Panel");
            RegisterPanel(_userWatchPanel, "&User Watch Panel");
            RegisterPanel(_configurationPanel, "&Configuration Panel");
            RegisterPanel(_breakpointsPanel, "&Breakpoints Panel");
            RegisterPanel(_fileSearchPanel, "&File Search Panel");
            RegisterPanel(_findPanel, "&Find && Highlight Panel");
            RegisterPanel(_commandPanel, "&Command Panel");
        }

        private void UnrealDebuggerIDE_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (IsWaitingForUDKResponse())
            {
                DialogResult result = MessageBox.Show("Unreal Debugger is waiting for a response from the UDK. Closing the debugger now may leave your game unstable. If you have compiled your scripts without debug information you can safely ignore this message. Do you want to force quit the debugger?", "Waiting for UDK", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);

                if (result == DialogResult.No)
                {
                    e.Cancel = true;
                }
            }
            else
            {
                SaveLayout();
                SaveProject();

                UnrealDebuggerIDE.Commands.ClearWatches();
                RaiseCommandEvent("stopdebugging", false);
            }
        }

        private void toolStripButtonContinue_Click(object sender, EventArgs e)
        {
            continueToolStripMenuItem.PerformClick();
        }

        private void toolStripButtonPause_Click(object sender, EventArgs e)
        {
            pauseToolStripMenuItem.PerformClick();
        }

        private void toolStripButtonStepInto_Click(object sender, EventArgs e)
        {
            stepIntoToolStripMenuItem.PerformClick();
        }

        private void toolStripButtonStepOver_Click(object sender, EventArgs e)
        {
            stepOverToolStripMenuItem.PerformClick();
        }

        private void toolStripButtonStepOut_Click(object sender, EventArgs e)
        {
            stepOutToolStripMenuItem.PerformClick();
        }

        private void continueToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Commands.Go();
        }

        private void pauseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Commands.Break();
        }

        private void stepIntoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Commands.StepInto();
        }

        private void stepOverToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Commands.StepOver();
        }

        private void stepOutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Commands.StepOut();
        }

        private void toggleBreakpointToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Document document = this.GetDocumentWithFocus();
            if (document != null)
            {
                document.ToggleBreakpointOnLine(document.GetCaretLine(), Keys.None);
            }
        }

        private void disableBreakpointToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Document document = this.GetDocumentWithFocus();
            if (document != null)
            {
                document.ToggleBreakpointOnLine(document.GetCaretLine(), Keys.Control);
            }
        }

        private void aboutUnrealDebuggerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox about = new AboutBox();
            about.ShowDialog();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("Are you sure you want to exit Unreal Debugger?", "Exit Unreal Debugger", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (result == DialogResult.Yes)
            {
                this.Close();
            }
        }

        private void viewHelpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://code.google.com/p/unreal-debugger/wiki/UnrealDebugger");
        }

        private void findResultsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FindResults results = this._findPanel.ContainsFocus ? this._findPanel.GetNextResults() : this._findPanel.GetResults();
            if (results != null) { this._findPanel.FocusResults(results); }
            this._findPanel.Show(this.dockPanelDebugger);
        }

        private void findAndHighlightToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this._findPanel.Show(this.dockPanelDebugger);
            this._findPanel.FocusInput();
        }

        private void findScriptFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this._fileSearchPanel.Show(this.dockPanelDebugger);
            this._fileSearchPanel.FocusInput();
        }

        private void documentOutlineToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this._outlinePanel.Show(this.dockPanelDebugger);
        }

        private void addUserWatchToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this._userWatchPanel.Show(this.dockPanelDebugger);
            this._userWatchPanel.FocusInput();
        }

        private void nextDocumentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowDocument(GetNextDocument());
        }

        private void previousDocumentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowDocument(GetPreviousDocument());
        }

        private void closeFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Document document = this.GetDocumentWithFocus();
            
            if (document != null)
            {
                document.Close();
            }
        }

        private void closeAllFilesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            List<Document> documents = this.GetOpenDocuments();

            foreach (Document document in documents)
            {
                document.Close();
            }
        }
    }
}
